package com.evaluation.kexingcp.psycho.evaluation.sys.evaluation

import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import arrow.core.raise.ensureNotNull
import arrow.core.right
import cn.hutool.core.date.DatePattern
import cn.hutool.core.date.DateUtil
import com.alibaba.fastjson.JSON
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.deepoove.poi.XWPFTemplate
import com.deepoove.poi.config.Configure
import com.deepoove.poi.data.ChartMultiSeriesRenderData
import com.deepoove.poi.data.Charts
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy
import com.evaluation.kexingcp.admin.api.entity.SysTenant
import com.evaluation.kexingcp.admin.service.SysDeptService
import com.evaluation.kexingcp.admin.service.SysTenantService
import com.evaluation.kexingcp.admin.service.SysUserService
import com.evaluation.kexingcp.common.data.tenant.TenantBroker
import com.evaluation.kexingcp.common.data.tenant.TenantContextHolder
import com.evaluation.kexingcp.psycho.evaluation.sys.controller.vo.EvaluationUserInfo
import com.evaluation.kexingcp.psycho.evaluation.sys.controller.vo.UserReportVo
import com.evaluation.kexingcp.psycho.evaluation.sys.entity.*
import com.evaluation.kexingcp.psycho.evaluation.sys.service.*
import com.evaluation.kexingcp.psycho.evaluation.sys.utils.FileService
import com.evaluation.kexingcp.psycho.evaluation.sys.utils.getUserInfo
import com.evaluation.kexingcp.psycho.evaluation.sys.utils.runInTransaction
import com.evaluation.kexingcp.psycho.evaluation.sys.utils.transpose
import org.slf4j.LoggerFactory
import org.springframework.beans.BeanUtils
import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.Resource
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.expression.EvaluationContext
import org.springframework.expression.ExpressionParser
import org.springframework.expression.spel.SpelParserConfiguration
import org.springframework.expression.spel.standard.SpelExpressionParser
import org.springframework.expression.spel.support.StandardEvaluationContext
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service
import org.springframework.transaction.support.TransactionTemplate
import org.springframework.web.client.RestTemplate
import java.nio.file.Files
import java.time.LocalDateTime
import java.util.*


data class FactorResult(
    val criticalValues: List<Double>,
    val result: String,
    val explain: String,
    val advise: String,
) {
    var score: Double = 0.0
    var factorResultId: Long = 0
    var factorName: String = ""
    val criticalLow = criticalValues[0]
    val criticalHigh = criticalValues[1]
}

data class Factor(
    val name: String,
    val isView: Boolean,
    val formula: String,
    var results: List<FactorResult>,
)

class Warning(
    val hit: String,
    val formula: String,
    val color: String,
    val level: String,
    val advise: String,
)
data class ReportDataItem(var value: Int? = null, val label: String? = null)
data class ReportData(val name: String? = null, val data: MutableList<ReportDataItem> = mutableListOf())

data class AreaLegendData(
    val area: MutableList<String> = mutableListOf(),
    val legend: MutableList<String> = mutableListOf("18岁以下", "18-25岁", "25-35岁", "35-45岁", "45岁以上"),
    var data: MutableList<MutableList<Int>> = mutableListOf(),
)


private val warningLevel = listOf("关注","普通","严重","紧急")

fun getFactorResult(warnings: List<Warning>): Warning? {
    if  (warnings.isEmpty()) return null

    var maxLevel = 0
    var res = warnings[0]
    for (warning in warnings) {
        val currLevel = warningLevel.indexOf(warning.level)
        if (currLevel > maxLevel) {
            maxLevel = currLevel
            res = warning
        }
    }

    return res
}

interface EvaluationService {
    fun evaluationScale(taskId: Long, scaleId: Long,answersRequest: AnswersRequest): Either<EvaluationError, Unit>
    fun evaluationScale(taskId: Long, scaleId: Long, userId: Long,answersRequest: AnswersRequest): Either<EvaluationError, Unit>
    fun generateReport(): Either<EvaluationError, Unit>
    fun generateReport(task: EvaluationTaskEntity, tenant: SysTenant): Either<EvaluationError, Unit>
    fun generalEvaluation(tenantId: Long, taskId: Long, scaleId: Long, req: GeneralRequest): Either<EvaluationError, Unit>
}

/**
 * G0：职业
 * G1：学历
 * G2：性别
 * G3：年龄
 * G4：月龄
 * G5：年级（1-12）
 * G6：文理科
 *
 * Q：题号
 * P：选项支序号
 * L：因子等级
 * F：因子序号
 *
 * &&：并且关系
 * ||：或者关系
 * ==：等于关系
 * ！=：不等于关系
 * ＞：大于关系
 * ＞=：大于等于
 * ＜：小于
 * ＜=：小于等于
 */
@Service
open class EvaluationServiceImpl(
    private val context: EvaluationContext,
    private val transactionTemplate: TransactionTemplate,
    private val evaluationScaleService: EvaluationScaleService,
    private val evaluationFactorService: EvaluationFactorService,
    private val evaluationWarningService: EvaluationWarningService,
    private val evaluationTaskService: EvaluationTaskService,
    private val evaluationFactorRecordsService: EvaluationFactorRecordsService,
    private val evaluationWarningRecordsService: EvaluationWarningRecordsService,
    private val redisTemplate: RedisTemplate<String, String>,
    private val fileService: FileService,
    private val evaluationTaskUserRelService: EvaluationTaskUserRelService,
    private val sysDeptService: SysDeptService,
    private val tenantService: SysTenantService,
    private val sysUserService: SysUserService,
    private val evaluationWarningManualReviewService: EvaluationWarningManualReviewService,
    private val evaluationGeneralResultService: EvaluationGeneralResultService
) : EvaluationService {

    val log = LoggerFactory.getLogger(EvaluationService::class.java)

    override fun evaluationScale(taskId: Long, scaleId: Long, answersRequest: AnswersRequest)
            : Either<EvaluationError, Unit> = evaluationScale(taskId, scaleId,getUserInfo().id, answersRequest)

    override fun evaluationScale(taskId: Long, scaleId: Long, userId: Long, answersRequest: AnswersRequest)
    : Either<EvaluationError, Unit>
    = runInTransaction(transactionTemplate) {
        val sysUser = sysUserService.getById(userId)
        val user = EvaluationUserInfo()
        BeanUtils.copyProperties(sysUser, user)
        user.id = userId
        user.deptList = sysDeptService.listParentDept(user.deptId).map { it.name }

        // 设置用户信息 * G0：职业 G1：学历 G2：性别 G3：年龄
        context.setVariable("G0", user.work)
        context.setVariable("G1", user.edu)
        context.setVariable("G2", user.sex)
        context.setVariable("G3", user.age)

        // 1. 读取量表因子
        val factors = evaluationFactorService
            .list(LambdaQueryWrapper<EvaluationFactorEntity>().eq(EvaluationFactorEntity::getScaleId, scaleId))
        // 1.1 分析因子结果，对应数据存取
        val factorsResult = mutableListOf<FactorResult>()
        val factorResultOption = mutableListOf<Long>() // 因子选项是L
        val factorResultScore = mutableListOf<Double>() // 因子得分是F
        for (curFactor in factors) {
            val factorResult = analyzeFactor(JSON.parseObject(curFactor.factor, Factor::class.java), answersRequest,factorResultScore, factorResultOption).bind()
            if (factorResult.factorResultId != 0L)
                factorsResult.add(factorResult)

            // 因子得分是F
            factorResultScore.add(factorResult.score)
            // 因子选择第几项是L
            factorResultOption.add(factorResult.factorResultId)
        }

        // 2. 读取预警信息
        val warnings = evaluationWarningService.list(
            QueryWrapper<EvaluationWarningEntity>().eq("scale_id", scaleId)
                .orderByAsc("warning_number")
        )

        val warningResult = analyzeWarning(warnings, factorResultOption).bind()

        val task = evaluationTaskService.getById(taskId)
        ensureNotNull(task) { TaskError("任务不存在") }
        val scale = evaluationScaleService.getById(scaleId)
        ensureNotNull(scale) { ScaleError("量表不存在") }

        // 插入评测结果表
        evaluationFactorRecordsService.save(
            EvaluationFactorRecordsEntity().also {
                it.taskId = taskId
                it.taskName = task.taskName
                it.scaleId = scaleId
                it.scaleName = scale.scaleName
                it.scaleType = scale.scaleVersion
                it.userId = user.id
                it.userInfo = JSON.toJSONString(user)
                it.evaluationResult = JSON.toJSONString(factorsResult)
                it.deptId = user.deptId
            }
        )

        // 插入预警结果表
        val warning = getFactorResult(warningResult)
        if (warning != null && task.taskLevel != 4) {
            evaluationWarningRecordsService.save(
                EvaluationWarningRecordsEntity().also {
                    it.taskId = taskId
                    it.taskName = task.taskName
                    it.scaleId = scaleId
                    it.scaleName = scale.scaleName
                    it.scaleType = scale.scaleVersion
                    it.userId = user.id
                    it.userInfo = JSON.toJSONString(user)
                    it.warningSource = JSON.toJSONString(warning)
                    it.warningLevel = warning.level
                    it.warningIssues = warning.hit
                    it.deptId = user.deptId
                }
            )
        }

        /**
         * 		SysMessageEntity sysMessage = new SysMessageEntity();
         * 		sysMessage.setSendFlag(YesNoEnum.YES.getCode());
         * 		baseMapper.update(sysMessage, Wrappers.<SysMessageEntity>lambdaQuery().eq(SysMessageEntity::getId, id));
         */
        // 评测管理表记录已完成
        val evaluationTaskUserEntity =  evaluationTaskUserRelService
            .getOne(QueryWrapper<EvaluationTaskUserRelEntity>()
                .eq("task_id", taskId).eq("user_id", user.id).eq("scale_id",scaleId))

        evaluationTaskUserEntity.completed = true
        evaluationTaskUserEntity.completedTime = LocalDateTime.now()
        evaluationTaskUserEntity.reportUrl = generatePersonalReport(factorsResult, user, scale)
        evaluationTaskUserRelService.updateById(evaluationTaskUserEntity)

        if (warning != null && task.taskLevel == 4) {
            // 人工审核接入
            // 1. 删除老的预警记录
            val warningEntities = evaluationWarningRecordsService.list(QueryWrapper<EvaluationWarningRecordsEntity>().eq("user_id", user.id).eq("scale_id", scaleId).eq("is_create_review", 1).orderByDesc("create_time"))
            if (warningEntities.size > 0) {
                val warningEntity = warningEntities[0]
                // 2. 转入人工审核
                evaluationWarningManualReviewService.save(
                    EvaluationWarningManualReviewEntity().also {
                        it.taskId = taskId
                        it.taskName = task.taskName
                        it.scaleId = scaleId
                        it.scaleName = scale.scaleName
                        it.scaleType = scale.scaleVersion
                        it.userId = user.id
                        it.userInfo = JSON.toJSONString(user)
                        it.warningSource = JSON.toJSONString(warning)
                        it.warningLevel = warning.level
                        it.warningIssues = warning.hit
                    }
                )
                evaluationWarningRecordsService.remove(QueryWrapper<EvaluationWarningRecordsEntity>().eq("user_id", user.id).eq("scale_id", scaleId).eq("is_create_review", 1))
            }
        }

        // 发送完成通知
        redisTemplate.convertAndSend(EVALUATION_CHANNEL, taskId.toString())

        Unit.right()
    }


    @Value("classpath:personal_report_template.docx") // resources 目录下的文件
    lateinit var personalReportTemplateResource: Resource

    private fun generatePersonalReport(
        factorResults: List<FactorResult>,
        user: EvaluationUserInfo,
        scale: EvaluationScaleEntity,
    ) : String {
        val policy = LoopRowTableRenderPolicy()

        val config = Configure.builder()
            .bind("factorResults", policy)
            .useSpringEL()
            .build()

        val template: XWPFTemplate = XWPFTemplate.compile(personalReportTemplateResource.inputStream, config).render(
            object : HashMap<String?, Any?>() {
                init {
                    put("factorResults", factorResults)
                    put("user", user)
                    put("scale", scale)
                    put("dept", user.deptList.reversed().joinToString("/"))
                    put("evaluationDate", DateUtil.format(Date(), DatePattern.NORM_DATE_PATTERN))
                    val names = factorResults.map { it.factorName }.toTypedArray()
                    val chart: ChartMultiSeriesRenderData = Charts
                        .ofMultiSeries("因子分数", factorResults.map { it.factorName }.toTypedArray())
                        .also { chars ->
                            factorResults.forEach {
                                val series = factorResults.indices.map { 0.0 }.toMutableList()
                                series[names.indexOf(it.factorName)] = it.score
                                chars.addSeries(it.factorName, series.toTypedArray())
                            }
                        }.create()

                    put("barChart", chart)
                }
            }
        )
        val temp = Files.createTempFile("output", ".docx")
        template.writeAndClose(temp.toFile().outputStream())
        return fileService.uploadFile(temp.toFile())
    }

    private fun analyzeFactor(factor: Factor, answersRequest: AnswersRequest, factorResultScore: MutableList<Double>, factorResultOption: MutableList<Long>)
    : Either<EvaluationError, FactorResult> = either {
        //1、读取因子结果

        if (factor.formula.contains("F")) { // 设置F变量
            for ((index, result) in factorResultScore.withIndex()) {
                context.setVariable("F${index + 1}", result)
            }
        } else if (factor.formula.contains("X")) {  // 单选选择了第几项
            for ((index, result) in answersRequest.answers.withIndex()) {
                context.setVariable("X${index + 1}", result.getSelectIdx())
            }
        }  else { // 设置Q，P 变量
            for ((index, result) in answersRequest.answers.withIndex()) {
                val answerVal = result.getScoreAndType()
                context.setVariable("${answerVal.first}${index + 1}", answerVal.second)
            }
        }

        for ((index, result) in factorResultOption.withIndex()) {
            context.setVariable("L${index + 1}", result)
        }

        val parser: ExpressionParser = SpelExpressionParser(
            SpelParserConfiguration(null, null, false, false, Integer.MAX_VALUE, Integer.MAX_VALUE))
        //2、表达式中以#varName的形式使用变量
        val expression = catch({ parser.parseExpression(factor.formula
            .replace("FLOOR", "#floor")
            .replace("GETMAX", "#getMax")
            .replace("GET", "#getIdx")
            .replace("MAX", "#max")
            .replace("G", "#G")  // 用户基本信息
            .replace("Q", "#Q")  // 单选
            .replace("P", "#P") // 多选
            .replace("L", "#L") // 因子结果第几项引用
            .replace("F", "#F") // 因子得分引用
            .replace("X", "#X") // 单选第几项引用
            )}) {
            raise(ParseExpressionError("解析因子${factor.name},表达式解析失败", factor.formula))
        }

        //3、在获取表达式对应的值时传入包含对应变量定义的EvaluationContext
        val score = catch({expression.getValue(context, Double::class.java)}) {
            raise(ParseExpressionError("解析因子${factor.name},表达式求值解析失败", factor.formula))
        }

        var factorResult = FactorResult(listOf(0.0, 0.0),"","","")
        factorResult.factorResultId = 0

        for ((index,result) in factor.results.withIndex()) {
            if (score >= result.criticalValues[0] && score < result.criticalValues[1]) {
                result.factorName = factor.name
                result.factorResultId = (index + 1).toLong()
                factorResult = result
            }
        }

        factorResult.score = score
        factorResult
    }

    private fun analyzeWarning(warningEntities: List<EvaluationWarningEntity>, factorResultScore: List<Long>)
    : Either<EvaluationError, List<Warning>> = either {
        val result = mutableListOf<Warning>()
        for (entity in warningEntities) {
            // 1 读取因子结果
            val context: EvaluationContext = StandardEvaluationContext()
            //1、设置变量

            // 等于结果的第几项
            for ((index, value) in factorResultScore.withIndex()) {
                context.setVariable("L${index + 1}", value)
            }
            val warning = JSON.parseObject(entity.warningContent, Warning::class.java)
            val parser: ExpressionParser = SpelExpressionParser()
            //2、表达式中以#varName的形式使用变量
            val expression = catch({parser.parseExpression(warning.formula.replace("L", "#L"))}) {
                raise(ParseExpressionError("解析预警${warning.hit},表达式解析失败", warning.formula))
            }
            //3、在获取表达式对应的值时传入包含对应变量定义的EvaluationContext
            val isWarning = catch({expression.getValue(context, Boolean::class.java)}) {
                raise(ParseExpressionError("解析预警${warning.hit},表达式求值解析失败", warning.formula))
            }

            if (isWarning) result.add(warning)
        }

        result
    }


//    @Scheduled(fixedRate = 1000 * 60 * 10) // 十分钟执行一次
    @Scheduled(fixedRate = 1000 * 60 * 1) // 十分钟执行一次
    override fun generateReport(): Either<EvaluationError, Unit> = either {
        log.info("定时任务生成报告.....")
        // 1 找出所有租户
        val tenants = tenantService.list()
        // 2 切换租户上下文
        for (tenant in tenants) {
            TenantBroker.applyAs(tenant.id) {
                // 3 执行对应的报表生成
                val tasks = evaluationTaskService.list(QueryWrapper<EvaluationTaskEntity>().eq("is_team_report_completed", 0).lt("task_level", 3))
                for (task in tasks) {
                    // 判断任务是否完成
                    val taskUserCount = evaluationTaskUserRelService.getTaskUserCount(task.id)
                    val taskCompleteCount = evaluationTaskUserRelService.getTaskUserCompletedCount(task.id)
                    // 查询所有的用户
                    val users = evaluationTaskUserRelService.getTaskUsers(task.id)
                    if (taskUserCount == taskCompleteCount) {
                        if (taskUserCount >= 5) {
                            val data = when (tenant.orgType) {
                                "中小学" -> schoolReport(task, users, tenant).bind()
                                "企业" -> enterpriseReport(task, users, tenant).bind()
                                else -> continue
                            }
                            task.taskReportData = data

                            task.isTeamReportCompleted = 1
                            evaluationTaskService.updateById(task)
                        }
                    }
                }
            }
        }
    }

    override fun generateReport(task: EvaluationTaskEntity, tenant: SysTenant): Either<EvaluationError, Unit> = either {
        // 判断任务是否完成
        val taskUserCount = evaluationTaskUserRelService.getTaskUserCount(task.id)
        val taskCompleteCount = evaluationTaskUserRelService.getTaskUserCompletedCount(task.id)
        // 查询所有的用户
        val users = evaluationTaskUserRelService.getTaskUsers(task.id)
        if (taskUserCount == taskCompleteCount) {
            if (taskUserCount >= 5) {
                val data = when (tenant.orgType) {
                    "中小学" -> schoolReport(task, users, tenant).bind()
                    "企业" -> enterpriseReport(task, users, tenant).bind()
                    else -> return@either
                }
                task.taskReportData = data

                task.isTeamReportCompleted = 1
                evaluationTaskService.updateById(task)
            }
        }
    }

    /**
     * 企业报告数据处理
     */
    private fun enterpriseReport(
        task: EvaluationTaskEntity,
        users: List<UserReportVo>,
        tenant: SysTenant,
    ) : Either<EvaluationError, String> = either {
        val sexData = users.groupingBy { it.sex }
            .aggregate { _, accumulator: Int?, _, first -> if (first) 1 else accumulator!! + 1 }

        val scales = users.first().factorResults.map { it.scaleName }
            .map { evaluationScaleService.getOne(QueryWrapper<EvaluationScaleEntity>().eq("scale_name", it)) }

        val ageData = users.groupingBy {
            when {
                it.age < 18 -> "18岁以下"
                it.age < 25 -> "18-25岁"
                it.age < 35 -> "25-35岁"
                it.age < 45 -> "35-45岁"
                else -> "45岁以上"
            }
        }.aggregate { _, accumulator: Int?, _, first ->
            if (first) 1 else accumulator!! + 1
        }

        val taskCompleteDate = evaluationTaskUserRelService.getTaskCompleteDate(task.id)
        val completeNums = mutableListOf<String>()
        val completeDate = mutableListOf<Int>()
        for (tcd in taskCompleteDate) {
            completeNums.add(tcd["date"].toString())
            completeDate.add(tcd["completeCount"].toString().toInt())
        }
        val completeData = mapOf(
            "completeNums" to completeNums,
            "completeDate" to completeDate
        )

        // 预警
        val warningData = users.groupingBy {
            if (it.warning) {
                "female"
            } else {
                "male"
            }
        }.aggregate { key, accumulator: ReportData?, element, first ->
            if (first) {
                val rd = ReportData(name = if (key == "female")  "预警" else "未预警")
                rd.data.add(ReportDataItem(1, element.deptName))
                rd
            } else {
                val reportVo = accumulator!!.data.first { it.label == element.deptName }
                reportVo.value = reportVo.value?.plus(1)

                accumulator
            }
        }

        // 男女对比
        val sexData2 = users.groupingBy {
            if (it.sex == "男") {
                "male"
            } else {
                "female"
            }
        }.aggregate { key, accumulator: ReportData?, element, first ->
            if (first) {
                val rd = ReportData(name = if (key == "male")  "男" else "女")
                rd.data.add(ReportDataItem(1, element.deptName))
                rd
            } else {
                val reportVo = accumulator!!.data.first { it.label == element.deptName }
                reportVo.value = reportVo.value?.plus(1)

                accumulator
            }
        }

        // 已婚未婚数据对比
        val marriageData = users.groupingBy {
            if (it.marriage == "未婚") {
                "male"
            } else {
                "female"
            }
        }.aggregate { key, accumulator: ReportData?, element, first ->
            if (first) {
                val rd = ReportData(name = if (key == "male")  "未婚" else "已婚")
                rd.data.add(ReportDataItem(1, element.deptName))
                rd
            } else {
                val reportVo = accumulator!!.data.first { it.label == element.deptName }
                reportVo.value = reportVo.value?.plus(1)

                accumulator
            }
        }

        // 个年龄段对比
        val acc = AreaLegendData()
        users.groupingBy {
            it.deptName
        }.aggregate { key, _: AreaLegendData?, element, first ->
            if (first) {
                acc.area.add(key)
                acc.data.add(MutableList(5) { 0 })
            }
            // 通过area找到部门的index
            val index = acc.area.indexOf(key)

            when {
                element.age < 18 -> {
                    acc.data[index][0] = acc.data[index][0].plus(1)
                }
                element.age < 25 -> {
                    acc.data[index][1] = acc.data[index][1].plus(1)
                }
                element.age < 35 -> {
                    acc.data[index][2] = acc.data[index][2].plus(1)
                }
                element.age < 45 -> {
                    acc.data[index][3] = acc.data[index][3].plus(1)
                }
                else -> {
                    acc.data[index][4] = acc.data[index][4].plus(1)
                }
            }
            acc
        }

        acc.data = transpose(acc.data)

        val user = sysUserService.getUserVoByUsername(task.createBy)
        val dept = sysDeptService.getById(task.deptId)

        // 构造一个map，把所有数组json化之后返回
        val map = mapOf(
            "completeData" to completeData,
            "sexData" to sexData,
            "ageData" to ageData,
            "taskCompleteDate" to taskCompleteDate,
            "warningData" to warningData,
            "sexData2" to sexData2,
            "areaLegendData" to acc,
            "task" to task,
            "users" to users,
            "scales" to scales,
            "taskCreateBy" to user.name,
            "deptName" to dept.name,
            "marriageData" to marriageData
        )

        JSON.toJSONString(map)
    }

    /**
     * 中小学报告数据处理
     */
    private fun schoolReport(
        task: EvaluationTaskEntity,
        users: List<UserReportVo>,
        tenant: SysTenant,
    ) : Either<EvaluationError, String> = either {
        val sexData = users.groupingBy { it.sex }
            .aggregate { _, accumulator: Int?, _, first -> if (first) 1 else accumulator!! + 1 }

        val scales = users.first().factorResults.map { it.scaleName }
            .map { evaluationScaleService.getOne(QueryWrapper<EvaluationScaleEntity>().eq("scale_name", it)) }

        val ageData = users.groupingBy {
            // 按6到18岁，每个年龄一个阶段统计
            when {
                it.age < 8 -> {"8岁以下"}
                it.age == 8 -> {"8岁"}
                it.age == 9 -> {"9岁"}
                it.age == 10 -> {"10岁"}
                it.age == 11 -> {"11岁"}
                it.age == 12 -> {"12岁"}
                it.age == 13 -> {"13岁"}
                it.age == 14 -> {"14岁"}
                it.age == 15 -> {"15岁"}
                it.age == 16 -> {"16岁"}
                it.age == 17 -> {"17岁"}
                it.age == 18 -> {"18岁"}
                else -> {"18岁以上"}
            }
        }.aggregate { _, accumulator: Int?, _, first ->
            if (first) 1 else accumulator!! + 1
        }

        val taskCompleteDate = evaluationTaskUserRelService.getTaskCompleteDate(task.id)
        val completeNums = mutableListOf<String>()
        val completeDate = mutableListOf<Int>()
        for (tcd in taskCompleteDate) {
            completeNums.add(tcd["date"].toString())
            completeDate.add(tcd["completeCount"].toString().toInt())
        }

        val completeData = mapOf(
            "completeNums" to completeNums,
            "completeDate" to completeDate
        )

        // 预警
        val warningData = users.groupingBy {
            if (it.warning) {
                "female"
            } else {
                "male"
            }
        }.aggregate { key, accumulator: ReportData?, element, first ->
            if (first) {
                val rd = ReportData(name = if (key == "female")  "预警" else "未预警")
                if (task.taskLevel == 0) {
                    rd.data.add(ReportDataItem(1, element.parentDeptName))
                } else {
                    rd.data.add(ReportDataItem(1, element.deptName))
                }
                rd
            } else {
                val reportVo =  if (task.taskLevel == 0) {
                    accumulator!!.data.firstOrNull { it.label == element.parentDeptName }
                } else {
                    accumulator!!.data.firstOrNull { it.label == element.deptName }
                }

                if (reportVo!=null) {
                    reportVo.value = reportVo.value?.plus(1)
                } else {
                    accumulator.data.add(ReportDataItem(1, if(task.taskLevel == 0) element.parentDeptName else element.deptName))
                }

                accumulator
            }
        }

        // 男女对比
        val sexData2 = users.groupingBy {
            if (it.sex == "男") {
                "male"
            } else {
                "female"
            }
        }.aggregate { key, accumulator: ReportData?, element, first ->
            if (first) {
                val rd = ReportData(name = if (key == "male")  "男" else "女")
                if (task.taskLevel == 0) {
                    rd.data.add(ReportDataItem(1, element.parentDeptName))
                } else {
                    rd.data.add(ReportDataItem(1, element.deptName))
                }
                rd
            } else {
                val reportVo =  if (task.taskLevel == 0) {
                    accumulator!!.data.firstOrNull { it.label == element.parentDeptName }
                } else {
                    accumulator!!.data.firstOrNull { it.label == element.deptName }
                }

                if (reportVo!=null) {
                    reportVo.value = reportVo.value?.plus(1)
                } else {
                    accumulator.data.add(ReportDataItem(1, if(task.taskLevel == 0) element.parentDeptName else element.deptName))
                }

                accumulator
            }
        }

        // 个年龄段对比
        val acc = AreaLegendData(legend = mutableListOf(
            "8岁以下",
            "8岁",
            "9岁",
            "10岁",
            "11岁",
            "12岁",
            "13岁",
            "14岁",
            "15岁",
            "16岁",
            "17岁",
            "18岁",
            "18岁以上"
        ))
        users.groupingBy {
            if (task.taskLevel == 0) it.parentDeptName
            else it.deptName
        }.aggregate { key, _: AreaLegendData?, element, first ->
            if (first) {
                acc.area.add(key)
                acc.data.add(MutableList(13) { 0 })
            }
            // 通过area找到部门的index
            val index = acc.area.indexOf(key)

            when {
                element.age < 8 -> {
                    acc.data[index][0] = acc.data[index][0].plus(1)
                }
                element.age == 8 -> {
                    acc.data[index][1] = acc.data[index][1].plus(1)
                }
                element.age == 9 -> {
                    acc.data[index][2] = acc.data[index][2].plus(1)
                }
                element.age == 10 -> {
                    acc.data[index][3] = acc.data[index][3].plus(1)
                }
                element.age == 11 -> {
                    acc.data[index][4] = acc.data[index][4].plus(1)
                }
                element.age == 12 -> {
                    acc.data[index][5] = acc.data[index][5].plus(1)
                }
                element.age == 13 -> {
                    acc.data[index][6] = acc.data[index][6].plus(1)
                }
                element.age == 14 -> {
                    acc.data[index][7] = acc.data[index][7].plus(1)
                }
                element.age == 15 -> {
                    acc.data[index][8] = acc.data[index][8].plus(1)
                }
                element.age == 16 -> {
                    acc.data[index][9] = acc.data[index][9].plus(1)
                }
                element.age == 17 -> {
                    acc.data[index][10] = acc.data[index][10].plus(1)
                }
                element.age == 18 -> {
                    acc.data[index][11] = acc.data[index][11].plus(1)
                }
                else -> {
                    acc.data[index][12] = acc.data[index][12].plus(1)
                }
            }

            acc
        }

        acc.data = transpose(acc.data)



        //if (filedName.contains("独生子女")) {
        //						title.add("独生子女(是,否)");
        //					} else if (filedName.contains("陪伴")) {
        //						title.add("陪伴情况(父母一方陪伴,留守儿童,父母双方陪伴)");
        //					} else if (filedName.contains("父母婚姻")) {
        //						title.add("父母婚姻(正常,再婚,单亲,离异)");
        //					} else if (filedName.contains("婚姻情况")) {
        //						title.add("婚姻情况(未婚、已婚、丧偶、再婚)");
        //					} else title.add(jsonObject.getString("fieldName"));

        // 独生子女
        val oneChildData = users.groupingBy {
            if (it.oneChild == "是") {
                "male"
            } else {
                "female"
            }
        }.aggregate { key, accumulator: ReportData?, element, first ->
            if (first) {
                val rd = ReportData(name = if (key == "male")  "独生" else "非独生")
                if (task.taskLevel == 0) {
                    rd.data.add(ReportDataItem(1, element.parentDeptName))
                } else {
                    rd.data.add(ReportDataItem(1, element.deptName))
                }
                rd
            } else {
                val reportVo =  if (task.taskLevel == 0) {
                    accumulator!!.data.first { it.label == element.parentDeptName }
                } else {
                    accumulator!!.data.first { it.label == element.deptName }
                }
                reportVo.value = reportVo.value?.plus(1)
                accumulator
            }
        }

        // 父母婚姻
        val parentMarriageData = AreaLegendData(legend = mutableListOf(
            "正常","再婚","单亲","离异"
        ))
        users.groupingBy {
            if (task.taskLevel == 0) it.parentDeptName
            else it.deptName
        }.aggregate { key, _: AreaLegendData?, element, first ->
            if (first) {
                parentMarriageData.area.add(key)
                parentMarriageData.data.add(MutableList(4) { 0 })
            }
            // 通过area找到部门的index
            val index = parentMarriageData.area.indexOf(key)

            when (element.parentMarriage) {
                "正常" -> {
                    parentMarriageData.data[index][0] = parentMarriageData.data[index][0].plus(1)
                }
                "再婚" -> {
                    parentMarriageData.data[index][1] = parentMarriageData.data[index][1].plus(1)
                }
                "单亲" -> {
                    parentMarriageData.data[index][2] = parentMarriageData.data[index][2].plus(1)
                }
                "离异" -> {
                    parentMarriageData.data[index][3] = parentMarriageData.data[index][3].plus(1)
                }
                else -> {

                }
            }

            parentMarriageData
        }

        // 陪伴情况
        val partnerStatusData = AreaLegendData(legend = mutableListOf(
            "父母一方陪伴","留守儿童","父母双方陪伴"
        ))
        users.groupingBy {
            if (task.taskLevel == 0) it.parentDeptName
            else it.deptName
        }.aggregate { key, _: AreaLegendData?, element, first ->
            if (first) {
                partnerStatusData.area.add(key)
                partnerStatusData.data.add(MutableList(3) { 0 })
            }
            // 通过area找到部门的index
            val index = partnerStatusData.area.indexOf(key)

            when (element.parentMarriage) {
                "父母一方陪伴" -> {
                    partnerStatusData.data[index][0] = partnerStatusData.data[index][0].plus(1)
                }
                "留守儿童" -> {
                    partnerStatusData.data[index][1] = partnerStatusData.data[index][1].plus(1)
                }
                "父母双方陪伴" -> {
                    partnerStatusData.data[index][2] = partnerStatusData.data[index][2].plus(1)
                }
                else -> {

                }
            }

            partnerStatusData
        }

        val user = sysUserService.getUserVoByUsername(task.createBy)
        val dept = sysDeptService.getById(task.deptId)

        // 构造一个map，把所有数组json化之后返回
        val map = mapOf(
            "completeData" to completeData,
            "sexData" to sexData,
            "ageData" to ageData,
            "taskCompleteDate" to taskCompleteDate,
            "warningData" to warningData,
            "sexData2" to sexData2,
            "areaLegendData" to acc,
            "task" to task,
            "users" to users,
            "scales" to scales,
            "taskCreateBy" to user.name,
            "deptName" to dept.name,
            "oneChildData" to oneChildData,
            "parentMarriageData" to parentMarriageData,
            "partnerStatusData" to partnerStatusData
        )

        JSON.toJSONString(map)
    }

    override fun generalEvaluation(tenantId: Long, taskId: Long, scaleId: Long,req: GeneralRequest): Either<EvaluationError, Unit> = either {

        TenantContextHolder.setUserName(req.user?.username)
        TenantBroker.runAs(tenantId) {
            // 设置用户信息 * G0：职业 G1：学历 G2：性别 G3：年龄
            context.setVariable("G0", req.user?.work)
            context.setVariable("G1", req.user?.edu)
            context.setVariable("G2", req.user?.sex)
            context.setVariable("G3", req.user?.age)


            // 1. 读取量表因子
            val factors = evaluationFactorService
                .list(LambdaQueryWrapper<EvaluationFactorEntity>().eq(EvaluationFactorEntity::getScaleId, scaleId))
            // 1.1 分析因子结果，对应数据存取
            val factorsResult = mutableListOf<FactorResult>()
            val factorResultOption = mutableListOf<Long>() // 因子选项是L
            val factorResultScore = mutableListOf<Double>() // 因子得分是F
            for (curFactor in factors) {
                val factorResult = analyzeFactor(JSON.parseObject(curFactor.factor, Factor::class.java), AnswersRequest(answers = req.answer),factorResultScore, factorResultOption).bind()
                if (factorResult.factorResultId != 0L)
                    factorsResult.add(factorResult)
            }

            // 2. 保存结果
            evaluationGeneralResultService.save(
                EvaluationGeneralResultEntity().also {
                    it.username = req.user?.username
                    it.mobile = req.user?.mobile
                    it.sex = req.user?.sex
                    it.age = req.user?.age
                    it.work = req.user?.work
                    it.edu = req.user?.edu
                    it.factorResult = JSON.toJSONString(factorsResult)
                    it.taskId = taskId
                    it.scaleId = scaleId
                }
            )
        }
    }
}